package com.zliuyno.rpcdemo.proxy;


import com.bjmashibing.system.rpcdemo.util.SerDerUtil;
import com.zliuyno.rpcdemo.rpc.Dispatcher;
import com.zliuyno.rpcdemo.rpc.Protocol.MyContent;
import com.zliuyno.rpcdemo.rpc.Protocol.MyHeader;
import com.zliuyno.rpcdemo.transport.ClientFactory;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.channel.ChannelFuture;
import io.netty.channel.socket.nio.NioSocketChannel;

import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.InetSocketAddress;
import java.util.concurrent.CompletableFuture;

public class MyProxy {

    public static <T> T proxyGet(Class<T> interfaceInfo) {
        //实现各个版本的动态代理

        ClassLoader loader = interfaceInfo.getClassLoader();
        Class<?>[] methodInfo = {interfaceInfo};

        Dispatcher dis = Dispatcher.getDis();

        //TODO: LOCAL REMOTE 实现：用到dispatcher 直接给你返回，还是本地调用的时候也代理一下


        return (T) Proxy.newProxyInstance(loader, methodInfo, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //在service方法执行的时候确定是本地的还是远程的，用dispatcher区分
                Object res;
                Object o = dis.get(interfaceInfo.getName());
//                System.out.println("=============" + o);
                if (o == null) {
                    //走rpc
                    String name = interfaceInfo.getName();
                    String methodName = method.getName();
                    Class<?>[] parameterTypes = method.getParameterTypes();

                    //TODO: rpc 就像小火车拉货 content是service的具体数据，但还需要header层完成IO传输的控制
                    MyContent content = new MyContent();
                    content.setArgs(args);
                    content.setName(name);
                    content.setMethodName(methodName);
                    content.setParameterTypes(parameterTypes);

                    //TODO:未来小火车可能会变

                    /**
                     * 1.缺失了注册发现 zk
                     * 2.第一层负载面向provider
                     * 3.consumer 可能是线程池   面向service
                     * serviceA
                     *      ipA:port
                     *          socket1
                     *          socket2
                     *      ipB:port
                     */

                    CompletableFuture<Object> resF = ClientFactory.transport(content);
                    res = resF.get();   //阻塞的

                } else {
                    //就是local
                    //插入一些插件的机会，支持扩展
                    System.out.println("local FC...........");
                    Class<?> clazz = o.getClass();
                    Method m = clazz.getMethod(method.getName(), method.getParameterTypes());
                    res = m.invoke(o, args);

                }

                return res;
            }

        });
    }
}
